//package com.jeesite.modules.utils;
//
//import com.jcraft.jsch.*;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//
//import java.io.*;
//import java.util.Properties;
//
//public class SshFileSync {
//    private static final Logger logger = LoggerFactory.getLogger(SshFileSync.class);
//    private static final int BUFFER_SIZE = 1024 * 1024;
//
//    public static void syncRemoteToLocal() throws Exception {
//        // 配置参数（建议移到配置文件）
//        String host = "sfe4-connect.simpfun.cn";
//        int port = 2079;
//        String user = "sfe2076391.dd713d51";
//        String password = "6435811309";
//        String remotePath = "/plugins/AuthMe/authme.db";
//        String localPath = "D:\\check\\authme.db";
//
//        Session session = null;
//        ChannelSftp channel = null;
//        InputStream in = null;
//        FileOutputStream out = null;
//
//        try {
//            // 1. 初始化JSch并创建会话
//            JSch jsch = new JSch();
//            enableJschDebugLog(); // 启用调试日志
//            session = jsch.getSession(user, host, port);
//            session.setPassword(password);
//
//            // 2. 现代算法配置（适配JSch 0.2.23社区版）
//            Properties config = new Properties();
//            config.put("StrictHostKeyChecking", "no");
//
//            // 密钥交换算法（优先现代椭圆曲线算法）
//            config.put("kex", "curve25519-sha256@libssh.org," +
//                    "ecdh-sha2-nistp521," +
//                    "diffie-hellman-group16-sha512," +
//                    "diffie-hellman-group-exchange-sha256");
//
//            // 加密算法（优先CTR模式）
//            config.put("cipher.c2s", "aes256-ctr,aes128-ctr,chacha20-poly1305@openssh.com");
//            config.put("cipher.s2c", "aes256-ctr,aes128-ctr,chacha20-poly1305@openssh.com");
//
//            // 消息认证算法（优先SHA-2）
//            config.put("mac.c2s", "hmac-sha2-512,hmac-sha2-256");
//            config.put("mac.s2c", "hmac-sha2-512,hmac-sha2-256");
//
//            // 主机密钥算法（支持ED25519和RSA）
//            config.put("hostkeyalgorithms", "ssh-ed25519,rsa-sha2-512,ecdsa-sha2-nistp256");
//
//            session.setConfig(config);
//            session.connect(5000); // 5秒超时
//            logger.info("SSH连接成功：{}:{}", host, port);
//
//            // 3. 打开SFTP通道
//            channel = (ChannelSftp) session.openChannel("sftp");
//            channel.connect(3000);
//            logger.info("SFTP通道已打开");
//
//            // 4. 确保本地目录存在
//            File localFile = new File(localPath);
//            if (!localFile.getParentFile().exists() && !localFile.getParentFile().mkdirs()) {
//                throw new IOException("创建本地目录失败：" + localFile.getParentFile());
//            }
//
//            // 5. 传输文件
//            in = channel.get(remotePath);
//            out = new FileOutputStream(localFile);
//
//            SftpATTRS fileAttrs = channel.lstat(remotePath);
//            long fileSize = fileAttrs.getSize();
//            long transferred = 0;
//            byte[] buf = new byte[BUFFER_SIZE];
//            int len;
//
//            while ((len = in.read(buf)) != -1) {
//                out.write(buf, 0, len);
//                transferred += len;
//                if (fileSize > 0 && transferred * 10 % fileSize == 0) {
//                    logger.info("传输进度：{}%（{}KB/{}KB）",
//                            (transferred * 100) / fileSize,
//                            transferred / 1024,
//                            fileSize / 1024);
//                }
//            }
//            logger.info("文件同步完成：{} → {}", remotePath, localPath);
//
//        } catch (JSchException e) {
//            logger.error("SSH连接失败：", e);
//            if (e.getMessage().contains("Algorithm negotiation fail")) {
//                throw new Exception("算法协商失败！请查看调试日志确认服务器支持的算法", e);
//            } else if (e.getMessage().contains("Auth fail")) {
//                throw new Exception("认证失败：用户名/密码错误", e);
//            } else {
//                throw new Exception("SSH异常：" + e.getMessage(), e);
//            }
//        } catch (SftpException e) {
//            logger.error("SFTP操作失败：", e);
//            // 兼容所有版本：通过异常消息判断错误类型（中文/英文消息都支持）
//            String msg = e.getMessage().toLowerCase();
//            if (msg.contains("no such file") || msg.contains("文件不存在")) {
//                throw new Exception("远程文件不存在：" + remotePath, e);
//            } else if (msg.contains("permission denied") || msg.contains("权限被拒绝")) {
//                throw new Exception("权限不足：无法读取" + remotePath, e);
//            } else if (msg.contains("connection closed") || msg.contains("连接已关闭")) {
//                throw new Exception("SFTP连接已关闭", e);
//            } else {
//                throw new Exception("SFTP操作异常：" + e.getMessage(), e);
//            }
//        } catch (IOException e) {
//            logger.error("文件IO失败：", e);
//            throw new Exception("本地文件操作异常：" + e.getMessage(), e);
//        } finally {
//            // 关闭资源
//            if (out != null) try { out.close(); } catch (IOException e) { logger.warn("关闭输出流失败", e); }
//            if (in != null) try { in.close(); } catch (IOException e) { logger.warn("关闭输入流失败", e); }
//            if (channel != null && channel.isConnected()) channel.disconnect();
//            if (session != null && session.isConnected()) session.disconnect();
//        }
//    }
//
//    /**
//     * 启用JSch调试日志，查看算法协商细节
//     */
//    private static void enableJschDebugLog() {
//        JSch.setLogger(new com.jcraft.jsch.Logger() {
//            @Override
//            public boolean isEnabled(int level) {
//                return level <= DEBUG;
//            }
//
//            @Override
//            public void log(int level, String message) {
//                if (message.contains("kex:") || message.contains("Cipher") || message.contains("MAC")) {
//                    logger.debug("JSch算法协商：{}", message);
//                }
//            }
//        });
//    }
//}
package com.jeesite.modules.utils;

import com.jcraft.jsch.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.Properties;

@Component
public class SshFileSync {
    private static final Logger logger = LoggerFactory.getLogger(SshFileSync.class);
    private static final int BUFFER_SIZE = 1024 * 1024;

    // 从配置文件注入注入所有参数（包括是否启用启用同步的开关）
    @Value("${sftp.sync.remote-host}")
    private String host;

    @Value("${sftp.sync.remote-port}")
    private int port;

    @Value("${sftp.sync.ssh-user}")
    private String user;

    @Value("${sftp.sync.ssh-password}")
    private String password;

    @Value("${sftp.sync.remote-file-path}")
    private String remotePath;

    @Value("${sftp.sync.local-file-path}")
    private String localPath;

    // 新增：同步功能启用开关（关键修正点）
    @Value("${sftp.sync.enabled}")
    private boolean syncEnabled;

    public void syncRemoteToLocal() throws Exception {
        // 修正：使用成员变量判断，不再直接在方法内使用@Value
        if (!syncEnabled) {
            logger.info("SFTP同步功能已禁用，跳过同步");
            return;
        }

        Session session = null;
        ChannelSftp channel = null;
        InputStream in = null;
        FileOutputStream out = null;

        try {
            // 1. 初始化JSch并创建会话
            JSch jsch = new JSch();
            enableJschDebugLog();
            session = jsch.getSession(user, host, port);
            session.setPassword(password);

            // 2. 现代算法配置
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            config.put("kex", "curve25519-sha256@libssh.org," +
                    "ecdh-sha2-nistp521," +
                    "diffie-hellman-group16-sha512," +
                    "diffie-hellman-group-exchange-sha256");
            config.put("cipher.c2s", "aes256-ctr,aes128-ctr,chacha20-poly1305@openssh.com");
            config.put("cipher.s2c", "aes256-ctr,aes128-ctr,chacha20-poly1305@openssh.com");
            config.put("mac.c2s", "hmac-sha2-512,hmac-sha2-256");
            config.put("mac.s2c", "hmac-sha2-512,hmac-sha2-256");
            config.put("hostkeyalgorithms", "ssh-ed25519,rsa-sha2-512,ecdsa-sha2-nistp256");

            session.setConfig(config);
            session.connect(5000);
            logger.info("SSH连接成功：{}:{}", host, port);

            // 3. 打开SFTP通道
            channel = (ChannelSftp) session.openChannel("sftp");
            channel.connect(3000);
            logger.info("SFTP通道已打开");

            // 4. 确保本地目录存在
            File localFile = new File(localPath);
            File parentDir = localFile.getParentFile();
            if (parentDir != null && !parentDir.exists()) {
                boolean mkdirSuccess = parentDir.mkdirs();
                if (!mkdirSuccess) {
                    throw new IOException("创建本地目录失败：" + parentDir.getAbsolutePath());
                }
                logger.info("已自动创建本地目录：{}", parentDir.getAbsolutePath());
            }

            // 5. 传输文件
            logger.info("开始同步文件：远程[{}] → 本地[{}]", remotePath, localPath);
            in = channel.get(remotePath);
            out = new FileOutputStream(localFile);

            SftpATTRS fileAttrs = channel.lstat(remotePath);
            long fileSize = fileAttrs.getSize();
            long transferred = 0;
            byte[] buf = new byte[BUFFER_SIZE];
            int len;

            while ((len = in.read(buf)) != -1) {
                out.write(buf, 0, len);
                transferred += len;
                if (fileSize > 0 && transferred * 10 % fileSize == 0) {
                    logger.info("文件传输进度：{}%（已传：{}KB / 总：{}KB）",
                            (transferred * 100) / fileSize,
                            transferred / 1024,
                            fileSize / 1024);
                }
            }

            logger.info("文件同步完成！远程文件大小：{}KB，本地文件已更新", fileSize / 1024);

        } catch (JSchException e) {
            logger.error("SSH连接/通道操作失败", e);
            if (e.getMessage().contains("Algorithm negotiation fail")) {
                throw new Exception("算法协商失败：远程服务器不支持配置的现代算法，请查看调试日志", e);
            } else if (e.getMessage().contains("Auth fail")) {
                throw new Exception("SSH认证失败：用户名[" + user + "]或密码错误", e);
            } else if (e.getMessage().contains("Connection timed out")) {
                throw new Exception("SSH连接超时：远程服务器[" + host + ":" + port + "]不可达", e);
            } else {
                throw new Exception("SSH操作异常：" + e.getMessage(), e);
            }
        } catch (SftpException e) {
            logger.error("SFTP文件操作失败", e);
            String msg = e.getMessage().toLowerCase();
            if (msg.contains("no such file") || msg.contains("文件不存在")) {
                throw new Exception("远程文件不存在：" + remotePath + "（请确认远程路径是否正确）", e);
            } else if (msg.contains("permission denied") || msg.contains("权限被拒绝")) {
                throw new Exception("SFTP权限不足：用户[" + user + "]无远程文件[" + remotePath + "]的读取权限", e);
            } else {
                throw new Exception("SFTP操作异常：" + e.getMessage(), e);
            }
        } catch (IOException e) {
            logger.error("本地文件IO操作失败", e);
            if (e.getMessage().contains("access denied") || e.getMessage().contains("拒绝访问")) {
                throw new Exception("本地权限不足：无法写入文件[" + localPath + "]（请检查本地目录读写权限）", e);
            } else {
                throw new Exception("本地文件操作异常：" + e.getMessage(), e);
            }
        } finally {
            // 关闭资源
            if (out != null) try { out.close(); } catch (IOException e) { logger.warn("关闭输出流失败", e); }
            if (in != null) try { in.close(); } catch (IOException e) { logger.warn("关闭输入流失败", e); }
            if (channel != null && channel.isConnected()) channel.disconnect();
            if (session != null && session.isConnected()) session.disconnect();
        }
    }

    private void enableJschDebugLog() {
        JSch.setLogger(new com.jcraft.jsch.Logger() {
            @Override
            public boolean isEnabled(int level) {
                return level <= DEBUG;
            }

            @Override
            public void log(int level, String message) {
                if (message.contains("kex:") || message.contains("Cipher") || message.contains("MAC") || message.contains("hostkey")) {
                    logger.debug("JSch调试[算法协商]：{}", message);
                }
            }
        });
    }
}
